#include <stdio.h>


/**
 * 测试字节序
 * date:2025-08-27
 */
void test_byte_order() {
    union {
        short s;
        char ch[sizeof(short)];
    } un;

    un.s = 0x0102;
    if (un.ch[0] == 1 && un.ch[1] == 2) 
        printf("this system is big-endian\n");
    else if (un.ch[0] == 2 && un.ch[1] == 1)
        printf("this system is little-endian\n");
    else
        printf("unknown");
}

/**
 * 测试字节序转换函数
 * date:2025-08-27 15:41
 */
#include <sys/types.h>
#include <netinet/in.h>
void test_transform_byte_order() {

    /*
     * uint16_t、uint32_t定义在<sys/types.h>头文件里
     */
    uint16_t s = 0x0102;
    uint32_t i = 0x01020102;
    
    /* 
     * 字节序转换函数，定义在<netinet/in.h>头文件里
     * 主机字节序转换为网络字节序：
     * uint16_t htons(uint16_t host16bitvalue);
     * uint32_t htonl(uint32_t host32bitvalue);
     * 
     * 网络字节序转换为主机字节序：
     * uint16_t ntohl(uint16_t net16bitvalue);
     * uint32_t ntohl(uint32_t net32bitvalue);
     * 
     * s表示short，指16位；l表示long，指32位，尽管在64位系统中l通常为64位，但这几个函数还是按32位操作的
     */

    uint16_t s_net = htons(s);
    printf("s_net = %#X\t", s_net);
    s = ntohs(s_net);
    printf("s = %#X\t", s);

    putchar('\n');

    uint32_t i_net = htonl(i);
    printf("i_net = %#X\t", i_net);
    i = ntohl(i_net);
    printf("i = %#X\n", i);

}

/**
 * 测试字节操纵函数
 * date:2025-08-27 16:18
 */
#include <strings.h>
#include <string.h>
void test_manipulate_byte() {
    /*
     * #include <strings.h>
     * 
     * 从dest指针开始，把nbytes个字节置为0
     * void bzero(void *dest, size_t nbytes);
     * 
     * 从src开始复制nbytes个字节到dest，src和dest可以重叠
     * void bcopy(const void *src, void *dest, size_t nbytes);
     * 
     * 比较nbytes个字节，若相同返回0，否则返回非0
     * int bcmp(const void *ptr1, const void *ptr2, size_t nbytes);
     * 
     * 以上三个函数不是c标准函数，是BSD标准的，常见与UNIX，下面三个才是c标准函数
     * 
     * #include <string.h>
     * void *memset(void *dest, int c, size_t len);
     * 
     * // memcpy的两个指针不能重叠，返回指针指向dest
     * void *memcpy(void *dest, const void *src, size_t nbytes);
     * 
     * // 比较结果：大于、小于、等于0
     * // 比较操作是假设这两个字节均为无符号字符的前提下展开的
     * int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);
     */

     char ch[10];
     size_t chars_len = sizeof(ch) / sizeof(char);
     printf("未初始化字节数组值：");
     for (size_t i = 0; i < chars_len; ++i)
        printf("%d ", ch[i]);

     puts("");

     memset(ch, 1, chars_len);
     printf("初始化为1后字节数组值：");
     for (size_t i = 0; i < chars_len; ++i)
        printf("%d ", ch[i]);

    printf("\n");

    char copy[10];
    void *ret_ptr = memcpy(copy, ch, chars_len);
    printf("copy数组值：");
     for (size_t i = 0; i < chars_len; ++i)
        printf("%d ", copy[i]);
    printf("\n");
    printf("ret_ptr is src ptr? %d\t", ret_ptr == ch);
    printf("ret_ptr is dest ptr? %d\n", ret_ptr == copy);


    bzero(ch, chars_len);
    printf("调用bzero()重置后字节数组值：");
     for (size_t i = 0; i < chars_len; ++i)
        printf("%d ", ch[i]);
    putchar('\n');

}


/**
 * ip地址转换函数
 * date：2025-08-27 17:30
 */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
void test_transform_in_addr() {
    /*
     * #include <arpa/inet.h>
     * 
     * 把点分十进制的ip地址字符串转换为网络字节序的ip地址
     * 返回：若ip字符串有效则为1，否则为0
     * 注：若addrptr为NULL，此函数仍然会执行ip字符串的有效性检查
     * int inet_aton(const char *strptr, struct in_addr *addrptr);
     * 
     * 返回：指向一个点分十进制字符串的指针
     * 注：返回的指针所指字符串驻留在静态内存中，这意味着该函数是不可重入的
     * char *inet_ntoa(struct in_addr inaddr);
     */

     // INET_ADDRSTRLEN定义在<netinet/in.h>头文件下，
     // #define INET_ADDRSTRLEN 16
     // #define INET6_ADDRSTRLEN 46

    const char ip[INET_ADDRSTRLEN] = "172.24.159.3";
    struct in_addr ip_number;
    int ret = inet_aton(ip, &ip_number);
    if (ret) 
        printf("ip addr = %d, 十六进制：%#X\n", ip_number.s_addr, ip_number.s_addr);
    else
        printf("字符串ip地址无效\n");
    
    char *ip_str = inet_ntoa(ip_number);
    printf("点分十进制ip地址为：%s\n", ip_str);


    /*
     * p表示presentation，n表示numeric
     * 
     * 返回：若成功则为1，若输入不是有效的表达式则为0，若出错则为-1
     * int inet_pton(int family, const char *strptr, void *addrptr);
     * 
     * len是strptr的长度，strptr不可以是空指针
     * 返回：若成功则为指向结果的指针（指向strptr），若出错则为NULL
     * const char* inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
     */

     struct in_addr ipv4_addr;
     int result = inet_pton(AF_INET, ip, &ipv4_addr);
     if (result) 
        printf("ip addr = %d, 十六进制：%#X\n", ipv4_addr.s_addr, ipv4_addr.s_addr);
    else
        printf("字符串ip地址无效\n");

    char *ipv4_str = (char*) malloc(sizeof(char) * INET_ADDRSTRLEN);
    const char *ret_ptr = inet_ntop(AF_INET, &ipv4_addr, ipv4_str, INET_ADDRSTRLEN);
    if (ret_ptr) {
        printf("点分十进制ip地址为：%s\n", ipv4_str);
        printf("ret_ptr == ipv4_str? %d\n", ret_ptr == ipv4_str);
    }
    free(ipv4_str);

}


/*
 * 套接字函数
 * #include <sys/socket.h>
 * int socket(int family, int type, int protocol);
 * 示例：socket(AF_INET, SOCK_STREAM, IPPROTO_CP); 表示ipv4的tcp套接字
 *
 * 
 * int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
 * 
 *
 * int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
 *
 * backlog指最大连接数（已建立TCP连接的和三次握手进行到一半的）
 * int listen(int sockfd, int backlog);
 *
 * int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
 * 
 */
